/**
 * Notes: 实体基类 
 * Date: 2021-03-15 19:20:00 
 * Ver : CCMiniCloud Framework 2.0.6 ALL RIGHTS RESERVED BY cclinux0730 (wechat)
 */

// 直接引用数据库工具类，避免循环依赖
const cloudDb = require('../../cloud/cloud_db.js');
const util = require('../../helpers/util.js');
const timeUtil = require('../../helpers/time_util.js');
const appCode = require('../../core/app_code.js');
const config = require('../../../config/config.js');

// 基础模型类
class BaseModel {
    /**
     * 构造函数
     * @param {*} table 表名
     */
    constructor(table = '') {
        this.TABLE = table;
        this.DB = cloudDb.getCloud().database();
        this.MAX_RECORD_SIZE = 500;
        this.DEFAULT_RECORD_SIZE = 20;
    }

    /**
     * 安全获取集合名称方法
     * @param {string} cl 集合名
     * @returns {string} 处理后的集合名
     */
    static C(cl) {
        // 特殊处理系统集合
        const systemCollections = ['admin', 'log', 'cache', 'setup'];
        if (systemCollections.includes(cl)) {
            return cl; // 系统集合直接使用无前缀
        }
        
        // 处理非系统集合
        const prefix = config.COLLECTION_PRFIX || '';
        if (prefix && !cl.startsWith(prefix)) {
            return prefix + cl;
        }
        
        return cl;
    }

    /**
     * 获取集合
     */
    getCollection() {
        return this.DB.collection(this.TABLE);
    }

    /**
     * 增加单个记录
     * @param {*} data 数据
     */
    async insert(data) {
        // 自动加上时间
        if (!util.isDefined(data.createTime))
            data.createTime = timeUtil.time();
        if (!util.isDefined(data.updateTime))
            data.updateTime = timeUtil.time();

        // 确保数据可安全序列化
        data = JSON.parse(JSON.stringify(data));

        const result = await this.getCollection().add({
            data
        });
        return result.id;
    }

    /**
     * 批量增加数据
     * @param {*} data 
     * @returns 返回插入成功的id列表
     */
    async insertBatch(datas = []) {
        if (!Array.isArray(datas) || datas.length == 0)
            return [];

        const batchTimes = Math.ceil(datas.length / 500);
        const tasks = [];
        for (let i = 0; i < batchTimes; i++) {
            const start = i * 500;
            const end = Math.min(datas.length, (i + 1) * 500);
            const curDatas = datas.slice(start, end);

            // 自动加上时间
            for (let data of curDatas) {
                if (!util.isDefined(data.createTime))
                    data.createTime = timeUtil.time();
                if (!util.isDefined(data.updateTime))
                    data.updateTime = timeUtil.time();
            }

            // 确保数据可安全序列化
            const safeData = JSON.parse(JSON.stringify(curDatas));

            const task = this.getCollection().add({
                data: safeData
            });
            tasks.push(task);
        }

        const results = await Promise.all(tasks);
        let ids = [];
        for (let result of results)
            ids = ids.concat(result.ids);
        return ids;
    }

    /**
     * 删除记录
     * @param {*} where 
     */
    async del(where) {
        return await this.getCollection().where(where).remove();
    }

    /**
     * 删除记录
     * @param {*} ids 
     */
    async deleteIds(ids) {
        if (!Array.isArray(ids) || ids.length == 0)
            return;

        ids = ids.map(id => id.trim());

        const MAX_RECORD_SIZE = 500;
        const query = this.getCollection();
        const batchTimes = Math.ceil(ids.length / MAX_RECORD_SIZE);
        const tasks = [];
        const db = cloudDb.getCloud().database();
        for (let i = 0; i < batchTimes; i++) {
            const start = i * MAX_RECORD_SIZE;
            const end = Math.min(ids.length, (i + 1) * MAX_RECORD_SIZE);
            const curIds = ids.slice(start, end);
            const _ = db.command;
            const task = query.where({
                _id: _.in(curIds)
            }).remove();
            tasks.push(task);
        }

        await Promise.all(tasks);
    }

    /**
     * 更新数据
     * @param {*} where 
     * @param {*} data 
     */
    async edit(where, data) {
        // 自动加上更新时间
        if (!util.isDefined(data.updateTime))
            data.updateTime = timeUtil.time();

        // 确保数据可安全序列化
        data = JSON.parse(JSON.stringify(data));

        return await this.getCollection().where(where).update({
            data
        });
    }

    /**
     * 根据ID更新数据
     * @param {*} id 
     * @param {*} data 
     */
    async editById(id, data) {
        // 自动加上更新时间
        if (!util.isDefined(data.updateTime))
            data.updateTime = timeUtil.time();

        // 确保数据可安全序列化
        data = JSON.parse(JSON.stringify(data));

        return await this.getCollection().doc(id).update({
            data
        });
    }

    /**
     * 批量更新数据
     * @param {*} ids 按ID更新
     * @param {*} data 
     */
    async editBatch(ids, data) {
        if (!Array.isArray(ids) || ids.length == 0 || !data)
            return;

        ids = ids.map(id => id.trim());

        // 确保数据可安全序列化
        data = JSON.parse(JSON.stringify(data));

        const MAX_RECORD_SIZE = 500;
        const batchTimes = Math.ceil(ids.length / MAX_RECORD_SIZE);
        const tasks = [];
        const db = cloudDb.getCloud().database();
        for (let i = 0; i < batchTimes; i++) {
            const start = i * MAX_RECORD_SIZE;
            const end = Math.min(ids.length, (i + 1) * MAX_RECORD_SIZE);
            const curIds = ids.slice(start, end);
            const _ = db.command;
            const task = this.getCollection().where({
                _id: _.in(curIds)
            }).update({
                data
            });
            tasks.push(task);
        }

        await Promise.all(tasks);
    }

    /**
     * 获取多条记录
     * @param {*} where 
     * @param {*} fields 
     * @param {*} orderBy 
     * @param {*} page 
     * @param {*} size 
     * @param {*} isTotal 
     * @returns 
     */
    async getList(where, fields = '*', orderBy = {}, page = 1, size = 10, isTotal = true) {
        page = Number(page);
        size = Number(size);

        let query = this.getCollection().where(where);
        
        if (fields != '*')
            query = query.field(fields);

        if (util.isObject(orderBy) && Object.keys(orderBy).length > 0) {
            for (let key in orderBy) {
                query = query.orderBy(key, orderBy[key].toLowerCase());
            }
        }

        const skip = (page - 1) * size;
        let list = [];
        if (isTotal) {
            const result = await query.limit(size).skip(skip).get();
            list = result.data;
        } else {
            // 不查询count
            const result = await query.limit(size).skip(skip).get();
            list = result.data;
        }

        let total = 0;
        if (isTotal) {
            // 总记录数
            const countResult = await this.getCollection().where(where).count();
            total = countResult.total;
        }

        // 确保数据可安全序列化
        list = JSON.parse(JSON.stringify(list));

        return {
            list,
            total
        };
    }

    /**
     * 根据ID获取单条记录
     * @param {*} id 
     * @param {*} fields 
     */
    async getById(id, fields = '*') {
        let query = this.getCollection().doc(id);
        if (fields != '*')
            query = query.field(fields);
        
        const result = await query.get();
        if (!result.data) return null;

        // 确保数据可安全序列化
        return JSON.parse(JSON.stringify(result.data));
    }

    /**
     * 根据条件获取单条记录
     * @param {*} where 
     * @param {*} fields 
     * @param {*} orderBy 
     * @returns 
     */
    async getOne(where, fields = '*', orderBy = {}) {
        let query = this.getCollection().where(where);
        if (fields != '*')
            query = query.field(fields);
            
        if (util.isObject(orderBy) && Object.keys(orderBy).length > 0) {
            for (let key in orderBy) {
                query = query.orderBy(key, orderBy[key].toLowerCase());
            }
        }
        
        const result = await query.limit(1).get();
        if (!result.data || result.data.length == 0) return null;

        // 确保数据可安全序列化
        return JSON.parse(JSON.stringify(result.data[0]));
    }

    /**
     * 获取所有记录
     * @param {*} where 
     * @param {*} fields 
     * @param {*} orderBy 
     * @param {*} size 默认100条
     */
    async getAllList(where, fields = '*', orderBy = {}, size = 100) {
        size = Number(size);
        if (size > this.MAX_RECORD_SIZE) size = this.MAX_RECORD_SIZE;
        
        let query = this.getCollection().where(where);
        if (fields != '*')
            query = query.field(fields);
            
        if (util.isObject(orderBy) && Object.keys(orderBy).length > 0) {
            for (let key in orderBy) {
                query = query.orderBy(key, orderBy[key].toLowerCase());
            }
        }
        
        const result = await query.limit(size).get();
        
        // 确保数据可安全序列化
        return JSON.parse(JSON.stringify(result.data));
    }
}

module.exports = BaseModel;